package com.itheima.a01;

import com.itheima.a01.测试组件.Component1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.io.IOException;

/*
    BeanFactory 与 ApplicationContext 的区别
 */
@SpringBootApplication
public class A01 {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {

        /*
        * SpringApplication.run(A01.class, args);使用这个去启动springboot的程序，
        * 有两个参数，第一个参数是引导类的类型，第二个参数是main方法传递过来的命令行参数。
        * 到底什么是 BeanFactory
                - 它是 ApplicationContext 的父接口
                - 它才是 Spring 的核心容器, ApplicationContext组合了BeanFactory的功能
        * */
        ConfigurableApplicationContext applicationContext = SpringApplication.run(A01.class, args);
        System.out.println(applicationContext);
        /*给大家演示下：*/
        /*下面的getBean()方法并不是applicationContext提供的，是BeanFactory提供的。
        * BeanFactory才是Spring的核心容器。*/
        /*根据名字从容器里面那取到对应的bean*/
        /*Object aaa = applicationContext.getBean("aaa");*/


        /*
            2. BeanFactory 能干点啥
                - 表面上只有 getBean
                - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
         */
        /*去拿到所有的私有的成员变量*/
//        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
//        /*因为是私有的，所以要setAccessible(true)*/
//        singletonObjects.setAccessible(true);
//        /*通过ApplicationContext拿到BeanFactory*/
//        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
//        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
//        System.out.println("遍历打印开始1---");
//        /*因为singletonObjects里面有很多个key value的形式，所以不方便看*/
//        map.forEach((k,v)->{
//            System.out.println(k+"="+v);
//        });
//        System.out.println("遍历打印结束1---");

        /*我们往容器里面放入了component1和component2,我们去容器里面拿取到component1和component2*/
//        System.out.println("遍历打印开始2---");
//        map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
//                .forEach(e -> {
//                    System.out.println(e.getKey() + "=" + e.getValue());
//                });
//        System.out.println("遍历打印结束2---");

        /*
            3. ApplicationContext 比 BeanFactory 多点啥
         */
        /*国际化处理*/
        /*applicationContext.getMessage()就是根据不同的key找到它的不同语言的翻译结果*/
//        System.out.println(applicationContext.getMessage("hi", null, Locale.CHINA));
//        System.out.println(applicationContext.getMessage("hi", null, Locale.ENGLISH));
//        System.out.println(applicationContext.getMessage("hi", null, Locale.JAPANESE));

        /*提供资源匹配的能力*/
        /*根据路径获取文件资源的能力*/
        /*classpath就是从类路径里面去找到这个资源*/
        /*file就是从磁盘文件里面去找到这个资源*/
//        Resource[] resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
//        for (Resource resource : resources) {
//            System.out.println(resource);
//        }

        /*从系统环境变量里面去获取值*/
//        System.out.println(applicationContext.getEnvironment().getProperty("java_home"));
//        System.out.println(applicationContext.getEnvironment().getProperty("server.port"));

        /*事件的发布，后面收事件就是监听器来收取事件*/
        /*在spring里面任何一个组件都可以作为监听器*/
//        applicationContext.publishEvent(new UserRegisteredEvent(applicationContext));

        /*在main方法里面触发Component1类里面的register()方法*/
        applicationContext.getBean(Component1.class).register();

        /*
            4. 学到了什么
                a. BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能
                b. 又新学一种代码之间解耦途径
            练习：完成用户注册与发送短信之间的解耦, 用事件方式、和 AOP 方式分别实现
         */
    }
}
